#include <libuutil.h>
#include <stddef.h>
#include "zpool_util.h"


typedef struct zpool_node {
	zpool_handle_t	*zn_handle;
	uu_avl_node_t	zn_avlnode;
	int		zn_mark;
} zpool_node_t;

struct zpool_list {
	boolean_t	zl_findall;
	uu_avl_t	*zl_avl;
	uu_avl_pool_t	*zl_pool;
	zprop_list_t	**zl_proplist;
};


typedef struct status_cbdata {
	int		cb_count;
	int		cb_name_flags;
	boolean_t	cb_allpools;
	boolean_t	cb_verbose;
	boolean_t	cb_explain;
	boolean_t	cb_first;
	boolean_t	cb_dedup_stats;
} status_cbdata_t;


/*typedef struct zpool_status_struct {
	const char *	pool_name;
	const char *	pool_status;
	zpool_status_t  pool_reason;
	uint_t			pool_children;
	uint_t			pool_mir_count;
	const char *	pool_mir_name;
	const char *	pool_mir_status;
	char			data[0];
}pool_status_st_t;
*/


typedef struct mir_status_struct
{
	char 	mir_name[40];
	char 	mir_status[10];
}mir_status_st_t;




void get_status_str(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
     int name_flags,int s,pool_status_st_t *pss,int *len)
{
	nvlist_t **child;
	uint_t c,children;
	vdev_stat_t *vs;
	char *vname;
	char *state;
	//int len = 0;

	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
	    &child, &children) != 0)
		children = 0;

	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
	    (uint64_t **)&vs, &c) == 0);

	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);

	//printf("%d\n",name);
	//printf("%d\n",state);

	if(s == 0)
	{
		pss->pool_children = children;
	}else if(s == 1)
	{
		pss->pool_mir_child_count = children;
		//pss->pool_mir_name = name;
		pss->pool_mir_status = state;
		//printf("%d\n",name);
		//printf("%d\n",state);
		//printf("mir_name:%s\n",pss->pool_mir_name);
		//printf("mir_status:%s\n",pss->pool_mir_status);
		
		memcpy(pss->pool_mir_name , name,strlen(name));
	
		//memcpy(pss->pool_mir_status , state,7);
	}else
	{
		char fill[40]="\0";                                              //定义sd*名字长度为40，状态长度为10。
		memcpy(&(pss->data[*len]),name,strlen(name));
		//printf("%d\n",*len);
		*len = *len + strlen(name);
		if(strlen(name) < 40)
		{
			memcpy(&(pss->data[*len]),fill,(40-strlen(name)));
		}
		*len = *len + (40-strlen(name));
		memcpy(&(pss->data[*len]),state,strlen(state));
		*len = *len + strlen(state);
		if(strlen(state) < 10)
		{
			memcpy(&(pss->data[*len]),fill,(10-strlen(state)));
		}
		*len = *len +(10-strlen(state));
		//printf("%d\n",*len);
	}
	
	
	for (c = 0; c < children; c++) {
		uint64_t islog = B_FALSE, ishole = B_FALSE;

		/* Don't print logs or holes here */
		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
		    &islog);
		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
		    &ishole);
		if (islog || ishole)
			continue;
		vname = zpool_vdev_name(g_zfs, zhp, child[c],
		    name_flags | VDEV_NAME_TYPE_ID);
		s = s+1;
		//printf("start:%d\n",len);
		get_status_str(zhp, vname, child[c],
		    name_flags,s,pss,len);
		free(vname);
	}

}




void get_pool_status_test(zpool_handle_t *zhp, void *data,pool_status_st_t *pss)
{
	status_cbdata_t *cbp = data;
	vdev_stat_t *vs;
	nvlist_t *config,*nvroot;
	uint_t c;
	zpool_status_t reason;
	char *msgid;
	zpool_errata_t errata;
	int s = 0;
	int len = 0;

	config = zpool_get_config(zhp, NULL);
	reason = zpool_get_status(zhp, &msgid, &errata);
	

	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
	    &nvroot) == 0);
	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
	    (uint64_t **)&vs, &c) == 0);


	pss->pool_name = zpool_get_name(zhp);
	pss->pool_status = zpool_state_to_name(vs->vs_state, vs->vs_aux);
	pss->pool_reason = reason;

	if(config != NULL)
	{
		/*
		nvlist_t **child;
		uint_t c,children;
		uint_t c1;
		vdev_stat_t *vs;
		char *vname;
		char *state;

		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
	    &child, &children) != 0)
		children = 0;

		pss->pool_children = children;

		for(c = 0;c < children;c ++){
			uint64_t islog = B_FALSE, ishole = B_FALSE;

			/* Don't print logs or holes here *
			(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
				&islog);
			(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
				&ishole);
			if (islog || ishole)
				continue;

			vname = zpool_vdev_name(g_zfs, zhp, child[c],
				cbp->cb_name_flags | VDEV_NAME_TYPE_ID);
			printf("%s\n",vname);

			verify(nvlist_lookup_uint64_array(child[c], ZPOOL_CONFIG_VDEV_STATS,
				(uint64_t **)&vs, &c1) == 0);

			state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
			printf("%s\n",state);
		}
		*/

		get_status_str(zhp, pss->pool_name,nvroot,cbp->cb_name_flags,s,pss,&len);

	}


	//pss->pool_children = children;

}



void * safe_malloc(size_t size)
{
	void *data;

	if ((data = calloc(1, size)) == NULL) {
		(void) fprintf(stderr, "internal error: out of memory\n");
		exit(1);
	}

	return (data);
}


uint_t num_logs(nvlist_t *nv)
{
	uint_t nlogs = 0;
	uint_t c, children;
	nvlist_t **child;

	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
	    &child, &children) != 0)
		return (0);

	for (c = 0; c < children; c++) {
		uint64_t is_log = B_FALSE;

		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
		    &is_log);
		if (is_log)
			nlogs++;
	}
	return (nlogs);
}




void zpool_no_memory(void)
{
	assert(errno == ENOMEM);
	(void) fprintf(stderr,
	    gettext("internal error: out of memory\n"));
	exit(1);
}


static int zpool_compare(const void *larg, const void *rarg, void *unused)
{
	zpool_handle_t *l = ((zpool_node_t *)larg)->zn_handle;
	zpool_handle_t *r = ((zpool_node_t *)rarg)->zn_handle;
	const char *lname = zpool_get_name(l);
	const char *rname = zpool_get_name(r);

	return (strcmp(lname, rname));
}



static int add_pool(zpool_handle_t *zhp, void *data)
{
	zpool_list_t *zlp = data;
	zpool_node_t *node = safe_malloc(sizeof (zpool_node_t));
	uu_avl_index_t idx;

	node->zn_handle = zhp;
	uu_avl_node_init(node, &node->zn_avlnode, zlp->zl_pool);
	if (uu_avl_find(zlp->zl_avl, node, NULL, &idx) == NULL) {
		if (zlp->zl_proplist &&
		    zpool_expand_proplist(zhp, zlp->zl_proplist) != 0) {
			zpool_close(zhp);
			free(node);
			return (-1);
		}
		uu_avl_insert(zlp->zl_avl, node, idx);
	} else {
		zpool_close(zhp);
		free(node);
		return (-1);
	}

	return (0);
}




zpool_list_t * pool_list_get(int argc, char **argv, zprop_list_t **proplist, int *err)
{
	zpool_list_t *zlp;

	zlp = safe_malloc(sizeof (zpool_list_t));

	zlp->zl_pool = uu_avl_pool_create("zfs_pool", sizeof (zpool_node_t),
	    offsetof(zpool_node_t, zn_avlnode), zpool_compare, UU_DEFAULT);

	if (zlp->zl_pool == NULL)
		zpool_no_memory();

	if ((zlp->zl_avl = uu_avl_create(zlp->zl_pool, NULL,
	    UU_DEFAULT)) == NULL)
		zpool_no_memory();

	zlp->zl_proplist = proplist;

	if (argc == 0) {
		(void) zpool_iter(g_zfs, add_pool, zlp);
		zlp->zl_findall = B_TRUE;
	} else {
		int i;

		for (i = 0; i < argc; i++) {
			zpool_handle_t *zhp;

			if ((zhp = zpool_open_canfail(g_zfs, argv[i]))) {
				if (add_pool(zhp, zlp) != 0)
					*err = B_TRUE;
			} else {
				*err = B_TRUE;
			}
		}
	}

	return (zlp);
}




int pool_list_iter(zpool_list_t *zlp, int unavail, zpool_iter_f func,
    void *data,pool_status_st_t *pss_all)
{
	zpool_node_t *node, *next_node;
	int ret = 0;
	int i = 0;

	for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next_node) {
		next_node = uu_avl_next(zlp->zl_avl, node);
		if (zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL ||
		    unavail)
		{
			//pool_status_st_t pss={0};

			//pool_status_st_t *pss = (pool_status_st_t*)malloc(sizeof(pool_status_st_t)+400*sizeof(char));

						
			pool_status_st_t *pss = (pool_status_st_t*)malloc(sizeof(pool_status_st_t));

			//ret |= func(node->zn_handle, data);
			get_pool_status_test(node->zn_handle, data,pss);                           //获取状态结构体

		//	memcpy(pss_all+i,pss,sizeof(pool_status_st_t)+400*sizeof(char));


			memcpy(pss_all+i,pss,sizeof(pool_status_st_t));

			free(pss);
		/*
			printf("name:%s\n",pss->pool_name);
			printf("status:%s\n",pss->pool_status);
			printf("children:%d\n",pss->pool_children);
			printf("mirror_count:%d\n",pss->pool_mir_count);
			printf("mir_name:%s\n",pss->pool_mir_name);
			printf("mir_status:%s\n",pss->pool_mir_status);
			char sd_na[9];
			char sd_st[11];
			memcpy(sd_na,pss->data,8);
			sd_na[8]='\0';
			//printf("len:%d\n",strlen(sd_na));
			memcpy(sd_st,&(pss->data[8]),10);
			sd_st[10]='\0';
			printf("sd_na:%s\n",sd_na);
			printf("sd_st:%s\n",sd_st);
			
		*/
			ret = 0;
		}
		i++;

	}

	return (ret);
}




void pool_list_free(zpool_list_t *zlp)
{
	uu_avl_walk_t *walk;
	zpool_node_t *node;

	if ((walk = uu_avl_walk_start(zlp->zl_avl, UU_WALK_ROBUST)) == NULL) {
		(void) fprintf(stderr,
		    gettext("internal error: out of memory"));
		exit(1);
	}

	while ((node = uu_avl_walk_next(walk)) != NULL) {
		uu_avl_remove(zlp->zl_avl, node);
		zpool_close(node->zn_handle);
		free(node);
	}

	uu_avl_walk_end(walk);
	uu_avl_destroy(zlp->zl_avl);
	uu_avl_pool_destroy(zlp->zl_pool);

	free(zlp);
}








int for_each_pool(int argc, char **argv, boolean_t unavail,
    zprop_list_t **proplist, zpool_iter_f func, void *data,pool_status_st_t *pss_all)
{
	zpool_list_t *list;
	int ret = 0;

	if ((list = pool_list_get(argc, argv, proplist, &ret)) == NULL)
		return (1);

	if (pool_list_iter(list, unavail, func, data,pss_all) != 0)
		ret = 1;

	pool_list_free(list);

	return (ret);
}


